<?php

require_once PATH_FFWD.'core/html_helpers.php';

class BaseForm extends BaseObject{
	public $input_className='dbinput';
	public $fields=Array();
	public $settings=Array();
	public $__sender=NULL;
	public function __construct(){
		global $app;
		$mceneed=0;
		$app->link('jquery_watermarkinput','js');
		if(isset($this->settings['resources'])){
			$app->link('jquery_uploadify','js');
			$app->link('jquery_resourcehandler','js');
			$app->link('jquery_contextmenu','js');
		}
		if(!isset($this->settings['method']))$this->settings['method']='POST';
		if(!isset($this->settings['postbuttontext']))$this->settings['postbuttontext']='Save';
		if(!isset($this->settings['class']))$this->settings['class']='';
		if(!isset($this->settings['submit']))$this->settings['submit']=1;
		$lp=strrpos($_SERVER['REQUEST_URI'],'?');
		if(!$lp)$lp=strlen($_SERVER['REQUEST_URI']);
		$this->fields['__sender']=Array(
			'value'=>substr($_SERVER['REQUEST_URI'],0,$lp),
		  'nq'=>1,
			'type'=>'varchar',
			'hidden'=>1,
		);
		foreach($this->fields as $k=>$v){
			if(!isset($this->fields[$k]['name']))$this->fields[$k]['name']=$k;
			if(isset($this->fields[$k]['join'])){
				//$this->fields[$k]['table']=
				if(!isset($this->settings['maintablename'])){
					reset($this->fields);
					if(preg_match('/`([a-zA-Z0-9_]*)`.*/',$this->fields[key($this->fields)]['query'],$out)){
						$this->settings['maintablename']=$out[1];
						$app->addJS('htmlselect');
					};
				}
				$this->fields[$k]['table']=$this->settings['maintablename'];

			}
			if(isset($this->fields[$k]['wysiwyg']))$mceneed=1;
		}
		if($mceneed){
			$app->addJS('tinymce/jquery.tinymce');
		}
		if(!isset($this->settings['colon']))$this->settings['colon']=0;
		if(isset($_GET['formdata']) ){
			$ser=base64_decode($_GET['formdata']);
			$des=unserialize($ser);
			if(isset($des['__sender']))unset($des['__sender']);
			//print_var($des);
			foreach($des as $k=>$v){
				if(isset($this->fields[$k])){
					if($this->fields[$k]['type']=='boolean')$v=1;
					$this->fields[$k]['value']=$v;
				}
			}
		}
	}

	public function __destruct(){
			
	}

	public function __toString(){
		$this->render();
	}

	public function renderOpen(){
		echo '<form ';
		if(!isset($this->settings[ACTION])){
			$this->settings[ACTION]=$this->settings['referrer'].'doedit.html';
		};
		if($this->settings[ACTION][0]!='/')$this->settings[ACTION]=$this->settings['referrer'].$this->settings[ACTION];
		echo 'action="'.$this->settings[ACTION].'" ';
		if(isset($this->settings['target']))echo 'target="'.$this->settings['target'].'" ';
		if(isset($this->settings['class'] ))echo 'class="'.$this->settings['class'].'" ';
		if(isset($this->settings['onsubmit']))echo ' onsubmit="'.$this->settings['onsubmit'].'" ';
		if(isset($this->settings['id']))echo ' id="'.$this->settings['id'].'" ';
		if(isset($this->settings['multipart'])){
			echo 'enctype="multipart/form-data" ';
			$this->settings['method']='POST';
		};
		echo 'method="'.$this->settings['method'].'" ';
		echo ' >';
		if(isset($this->settings['headertemplatefn']))include $this->settings['headertemplatefn'];
	}

	public function renderClose(){
		if(isset($this->settings['footertemplatefn']))include $this->settings['footertemplatefn'];
		else{
			echo "<ul class='form_row'>";
			if(!isset($this->settings['nocaptions']))
			echo "<li class='".($this->settings['class']?$this->settings['class'].' ':'')."form_col_caption'>&nbsp;</li>\n".
					 "<li class='".($this->settings['class']?$this->settings['class'].' ':'')."form_col_input'>";
				
			
			if($this->settings['submit']){
				echo html_input(Array(
					'type'=>'submit',
					'class'=>$this->input_className,
					'value'=>translate($this->settings['postbuttontext']),
				));
			};
			if($this->settings['delete'] && (!isset($this->fields['id']) || isset($this->fields['id']['value']))){
				echo html_input(Array(
					'type'=>'button',
					'class'=>$this->input_className,
					'value'=>translate('Delete'),
					'onclick'=>js_redirect($this->settings['referrer'].'delete.html',1),
				));
			}
				
			echo "</li></ul>";
		}
		echo '</form>';
	}

	public function renderRow(Array &$field,$fieldname=''){
		if(!$field)throw new Exception('BaseForm::renderRow() called without argument');
		if(isset($field['hidden'])){
			echo '<div style="display:none;">';
		}
		if(isset($this->settings['rowtemplatefn']))include $this->settings['rowtemplatefn'];
		else{
			echo '<ul class="'.($this->settings['class']?$this->settings['class'].' ':'').'form_row">';
			if($fieldname && !isset($this->settings['nocaptions'])){
				if(isset($field['caption']))
				$caption=$field['caption'];
				else
				$caption=translate($fieldname);
				echo '<li class="'.($this->settings['class']?$this->settings['class'].' ':'').'form_col_caption">'.$caption;
				if(isset($field['required']))echo '*';
				if($this->settings['colon'] && !isset($field['nocolon']) && $field['type']!='boolean' &&
				$field['type']!='none'  && $caption[strlen($caption)-1]!='?')echo ':';
				echo "</li>\n";
			}
			echo '<li class="'.($this->settings['class']?$this->settings['class'].' ':'').'form_col_input"';
			if(!($fieldname && !isset($this->settings['nocaptions'])))
			echo " style='width:100%;' ";
			echo '>'.$this->renderInput($fieldname)."</li>\n";
			echo '</ul>';
		}
		if(isset($field['hidden']))echo '</div>';
	}

	public function renderInput($name,$p=Array()){
		if(!isset($this->fields[$name]))throw new Exception('Field does not exist in the form\'s dataset');
		$field=&$this->fields[$name];
		if(!is_array($field))throw new Exception('Field definition error');

		if(isset($field['hidden']) && $field['hidden'])$func='html_input_hidden';
		else	$func='html_input_'.$field['type'];
		if(isset($field['validator']) && $field['validator']->regexp){
			$p['onblur']=js_validatebyregexp($field['validator']->regexp);
		};
		$p=array_merge($field,$p);

		if(!isset($p['class']))$p['class']=$this->input_className;
		$p['class']=$this->settings['class'].' '.$p['class'];

		if(isset($_GET[$name]) && !$field['value'])$field['value']=$_GET[$name];

		$pre='';
		if(isset($_GET['error_'.$name])){
			//$p['class'].=' invalidvalue';
			$pre.='<div class="'.($this->settings['class']?$this->settings['class'].' ':'').'inputfielderror">'.translate(geterrorstring($_GET['error_'.$name])).'</div>';
		}

		return $func($p).$pre;
	}

	public function render($p=Array()){
		$this->settings=array_merge($this->settings,$p);


		if(!isset($this->settings['referrer'])){
			$pl=strrpos($_SERVER['REQUEST_URI'],'/');
			$this->settings['referrer']=substr($_SERVER['REQUEST_URI'],0,$pl).'/';
		};
		if(!isset($this->settings['delete']))$this->settings['delete']=1;
		$this->renderOpen();
		if(isset($this->fields[key($this->fields)]['order']))
		uksort($this->fields, 'BaseForm::fieldsortfunc');

		foreach($this->fields as $k=>&$v){
			//if($k=='__sender')continue;
			$this->renderRow($v,$k);
		}
		$this->renderClose();
		if(isset($this->settings['resources']) && $this->settings['resources']){
			$ref=substr($this->settings['referrer'],strpos($this->settings['referrer'],'.php')+4,-1);
			if($ref[0]=='/')$ref=substr($ref,1);
			js_resourcehandler(Array('folder'=>$ref));
		}
	}

	/**
	 * Receives an array, validates
	 * and sets the value of the internal fields.
	 * /processes the response sent by itself/
	 */

	public function process(Array $data){
		//print_var($data);exit;
		$error=Array();
		if(isset($data['__sender'])){
			$lp=strrpos($data['__sender'], '?');if(!$lp)$lp=strlen($data['__sender']);
			$this->__sender=substr($data['__sender'],0,$lp);
		}
		foreach($this->fields as $k=>&$field){
			if($k=='__sender')continue;
			if(!isset($data[$k]))$data[$k]=NULL;
			if(isset($field['validator'])){
				$error[$k]=$field['validator']->validateValue($data[$k]);
				if(!$error[$k])unset($error[$k]);
			}
			if(!isset($error[$k]) && isset($data[$k])){
				if($field['type']=='boolean')
				$field['value']=1;
				else
				$field['value']=$data[$k];
			}
		};
		if(!empty($error)){
			$this->redirectWithErrorMessages($error);
		}
	}

	public function save(BaseRecord &$e=NULL){
		try{
			foreach($e->fields as $k=>&$v){
				if($k=='id')continue;
				if(isset($this->fields[$k])){
					
					if(isset($this->fields[$k]['value'])){
						$e->$k=$this->fields[$k]['value'];
					}else
						$e->$k=NULL;
				}
			}
		}catch(Exception $ex){
			return 1;
		};
		try{
			$res=$e->save();
		}catch(Exception $e){
			if(get_class($e)=='MySQLException'){
				if($e->isCannotBeNull()){
					return Array($e->getSubject()=>"must_be_filled");
				}
			};			
		};
		return $res;
	}

	public function getFieldValue($fieldname){
		if(!isset($this->fields[$fieldname]))throw new Exception('Field "'.$fieldname.'" doesn not exist in form');
		return @$this->fields[$fieldname]['value'];
	}

	public function __call($func,$param){
		if(substr($func,0,3)=='get'){
			return $this->getFieldValue(strtolower(substr($func,3)));
		};
		throw new Exception('Method "'.$func.'" does not exist');
	}

	public function redirectWithErrorMessages($errors){
		if(is_string($errors)){
			$errors=removeaccents($errors);
			$a=explode('_',$errors);
			$errors=Array($a[0]=>$errors);
		}
		global $app;
		$p=Array();
		if(isset($this->fields['__sender']))unset($this->fields['__sender']);
		
		$p['formdata']=Array();
		foreach($this->fields as $k=>&$v){
			if(isset($this->fields[$k]['value']) && $this->fields[$k]['value'])$p['formdata'][$k]=$this->fields[$k]['value'];
		};
		foreach($errors as $k=>$v){
			$p['error_'.$k]=$v;
		};
		$p['formdata']=base64_encode(serialize($p['formdata']));
		//$url=link_for($this->__sender);
		$url=$this->__sender.array_to_urlgetparam($p).'#form';
		//obflush();echo $url;exit;
		$app->redirectTo($url);
	}

	public function getErrorMessagesAsGetParam(){
		$param='';
		return $param;
	}

	public function loadfromrecord($e){
		$flds=array_keys($e->fields);
		foreach($flds as $fld){
			if(isset($this->fields[$fld]))$this->fields[$fld]['value']=(string)$e->$fld;
		}
		if($e->id && (string)$e->id=='new'){
			$this->settings['delete']=0;
		}
		return NULL;
	}

	public function load($e){
		return $this->loadfromrecord($e);
	}


	//==== S T A T I C ===============

	static function generate($tablename){
		$t=$tablename.'Table';
		$t=new $t();
		$fields=$t->getFields();
		$clsdef="<?php\nclass ".$tablename."Form extends BaseForm{\n\tpublic function __construct(){\n";
		foreach($fields as $k=>$v){
			$clsdef.="\n\t\t\$this->fields['".$k."']=".$tablename."Table::\$fields['".$k."'];";
		}

		$clsdef.="\n\t//calling base class's constructor\n".
		"\t\tparent::__construct();\n".	
		"\t}\n".
		"};\n";
		$outfn=PATH_CONFIG.'forms/form.'.$tablename.'.php';
		if(!is_dir(dirname($outfn)))mkdir(dirname($outfn),0777,1);
		if(!file_exists($outfn)){
			file_put_contents($outfn,$clsdef);
			chmod($outfn, 0777);
		}
	}

	static function fieldsortfunc(&$a,&$b){
		if(isset($a['order']) && isset($b['order'])){
			if($a['order']>$b['order'])return 1;
			else
			if($a['order']<$b['order'])return -1;
		};
		return 0;
	}

	protected function generateTemplate($tplfn){
		if(!is_dir(dirname($tplfn)))mkdir(dirname($tplfn),0777,1);

		/*======================*/

		if(isset($this->fields[key($this->fields)]['order']))
		uksort($this->fields, 'BaseForm::fieldsortfunc');
			
			
		$tpl="<table class=''>\n\t<thead>\n\t</thead>\n\t<tbody>\n";
		foreach($this->fields as $k=>&$v){
			$tpl.="\t<tr ";
			if(isset($v['hidden']))$tpl.=" style='display:none;' ";else	$tpl.=" class='form_row' ";
			$tpl.=">\n\t\t<td class='form_col_caption'>";
			$tpl.="<?=translate('$k');?>";
			if(isset($v['required']))$tpl.='*';
			$tpl.="</td>\n\t\t<td class='form_col_input'>";
			$tpl.="<?=\$this->renderInput('$k');?>";
			$tpl.="</td>\n\t</tr>\n";
		}
		$tpl.="\t</tbody>\n\t<tfoot>\n\t</tfoot>\n</table>\n";
		$tpl="<?php \$this->renderOpen(); ?>\n".$tpl."<?php \$this->renderClose(); ?> ";
		file_put_contents($tplfn,$tpl);
	}

	public function renderwithtemplate($tplfn=NULL){
		if($tplfn===NULL){
			$tplfn=strtolower('config/forms/templates/'.substr(get_class($this),0,-4).'/default.html');
		};
		if(file_exists($tplfn)){
			if(!isset($this->settings['referrer'])){
				$pl=strrpos($_SERVER['REQUEST_URI'],'/');
				$this->settings['referrer']=substr($_SERVER['REQUEST_URI'],0,$pl).'/';
			};
			if(!isset($this->settings['delete']))$this->settings['delete']=1;
			/* ============== */
			include $tplfn;
			/* ============== */
			if(isset($this->settings['resources'])){
				$ref=substr($this->settings['referrer'],strpos($this->settings['referrer'],'.php')+4,-1);
				if($ref[0]=='/')$ref=substr($ref,1);
				js_resourcehandler($ref);
			}
		}else{
			$this->generateTemplate($tplfn);
			$this->renderwithtemplate($tplfn);
		}
	}

	public function addCaptcha(){
		$this->fields['captcha']=Array(
			'name'=>'captcha',
			'type'=>'captcha',
			'size'=>4,
			'validator'=>new FieldvalidatorCaptcha(),
		);
	}
}
